package com.xqboss.apps.service.nft;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.dozermapper.core.DozerBeanMapperBuilder;
import com.github.dozermapper.core.Mapper;
import com.xqboss.apps.domain.marketing.ThemePage;
import com.xqboss.apps.domain.marketing.vo.MarketingRightsCardVO;
import com.xqboss.apps.domain.marketing.vo.PageResponseVO;
import com.xqboss.apps.domain.nft.*;
import com.xqboss.apps.vo.nft.HoldPictureVO;
import com.xqboss.apps.vo.nft.NftCirculateVO;
import com.xqboss.apps.vo.nft.NftRepertorySeparationVo;
import com.xqboss.apps.vo.nft.NftOldVO;
import com.xqboss.apps.dto.nft.*;
import com.xqboss.apps.enums.nft.CommonBooleanEnum;
import com.xqboss.apps.mapper.member.SysUserNftMapper;
import com.xqboss.apps.mapper.nft.NftOldMapper;
import com.xqboss.apps.service.marketing.MarketingRightsCardService;
import com.xqboss.apps.service.marketing.ThemePageService;
import com.xqboss.common.constant.HttpStatus;
import com.xqboss.common.core.domain.entity.SysDictData;
import com.xqboss.common.core.redis.RedisCache;
import com.xqboss.apps.enums.nft.TargetTypeEnum;
import com.xqboss.common.exception.ServiceException;
import com.xqboss.common.utils.DateUtils;
import com.xqboss.apps.util.mh.CommonUtil;
import com.xqboss.system.service.ISysDictDataService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RBucket;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * nftService业务层处理
 *
 * @author xqboss
 * @date 2023-08-02
 */
@Service
public class NftOldService extends ServiceImpl<NftOldMapper, NftOld> {

    final String nftCirculateGrossRedis = "nft_circulate_gross_redis";
    final String numberOfHolders = "number_of_holders";
    final String nftRepertorySeparationCreatebeforeRedis = "nft_repertory_separation_createbefore_redis_";

    @Resource
    private NftOldMapper nftOldMapper;
    @Resource
    private ISysDictDataService sysDictDataService;
    @Resource
    private ChainSeriesService chainSeriesService;
    @Autowired
    private ThemePageService pageService;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private NftNumberService nftNumberService;
    @Autowired
    private NftCategoryService nftCategoryService;
    @Autowired
    private NftBeforeRuleService nftBeforeRuleService;
    @Autowired
    private ExclusiveBuyService exclusiveBuyService;
    @Autowired
    private NftAttrService nftAttrService;
    @Autowired
    private PrizeGiftService prizeGiftService;
    @Autowired
    private MarketingRightsCardService rightsCardService;
    @Resource
    private SysUserNftMapper sysUserNftMapper;
    @Autowired
    private NftOldService nftOldService;
    @Autowired
    private NftRepertorySeparationService nftRepertorySeparationService;
    @Resource
    private NftSellCalendarService nftSellCalendarService;
    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 查询nft
     *
     * @param id nft主键
     * @return nft
     */
    public NftOld selectNftById(Long id) {
        return nftOldMapper.selectNftById(id);
    }

    /**
     * 查询nft列表
     *
     * @param nftOld nft
     * @return nft
     */
    public List<NftOld> selectNftList(NftOld nftOld) {
        return nftOldMapper.selectNftList(nftOld);
    }

    /**
     * 新增nft
     *
     * @param nftOld nft
     * @return 结果
     */
    public int insertNft(NftOld nftOld) {
        nftOld.setCreateTime(DateUtils.getNowDate());
        return nftOldMapper.insertNft(nftOld);
    }

    /**
     * 修改nft
     *
     * @param nftOld nft
     * @return 结果
     */
    public int updateNft(NftOld nftOld) {
        nftOld.setUpdateTime(DateUtils.getNowDate());
        return nftOldMapper.updateNft(nftOld);
    }

    /**
     * 批量删除nft
     *
     * @param ids 需要删除的nft主键
     * @return 结果
     */
    public int deleteNftByIds(Long[] ids) {
        return nftOldMapper.deleteNftByIds(ids);
    }

    /**
     * 删除nft信息
     *
     * @param id nft主键
     * @return 结果
     */
    public int deleteNftById(Long id) {
        return nftOldMapper.deleteNftById(id);
    }

    public List<ChainLevelDTO> getNftLevel(Integer targetType) {
        // 判断是宠物藏品还是其他藏品，展示不同等级
        String key;
        if (targetType.equals(TargetTypeEnum.PET.value)) {
            key = "pet_level";
        } else {
            key = "nft_level";
        }
        SysDictData sysDictData = sysDictDataService.selectByType(key);
        List<ChainLevelDTO> chainLevelDTOS = new ArrayList<>();
        List<String> strings = CommonUtil.stringToStringList(sysDictData.getDictValue(), ";");
        for (String string : strings) {
            List<String> stringList = CommonUtil.stringToStringList(string, ",");
            Integer levelId = Integer.valueOf(stringList.get(0));
            String levelName = stringList.get(1);
            chainLevelDTOS.add(levelDTOBuild(levelId, levelName));
        }
        return chainLevelDTOS;
    }

    private ChainLevelDTO levelDTOBuild(Integer levelId, String levelName) {
        ChainLevelDTO chainLevelDTO = new ChainLevelDTO();
        chainLevelDTO.setLevelId(levelId);
        chainLevelDTO.setLevelName(levelName);
        return chainLevelDTO;
    }

    @Transactional(rollbackFor = Exception.class)
    public void createNft(NftOldDTO dto) {
        if (ObjUtil.isNull(dto)) {
            throw new ServiceException("参数不能为空 ！");
        }
        NftOld nftOld = new NftOld();
        dto.setBlockChain(0);   // 是否上链
        BeanUtils.copyProperties(dto, nftOld);
        // 保存文章id
        List<Integer> ids = dto.getArticle();
        if (CollUtil.isNotEmpty(ids)) {
            nftOld.setArticles(ids.toString());
        }
        // 设置库存
        nftOld.setInitialStock(nftOld.getStock() + nftOld.getExtraStock());
        // 首发库存
        nftOld.setFirstStock(nftOld.getStock());//不变
        // 设置藏品编号前缀
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("prefix", CommonUtil.getNftPrefix());
        nftOld.setNftExtra(jsonObject.toJSONString());

        // 添加的藏品类型为宠物, 创建铸造器(孵化器)数据, 宠物配置, 派系, 种族
        if (dto.getNftType().equals(NftOld.NftTypeEnum.PET.getValue())) {
            ChainSeriesDTO chainSeriesDTO = dto.getChainSeriesDTO();
            // 创建宠物时在基础信息中设置宠物模板时设置的组件内容, 必选项, 不能为空
            if (CollUtil.isEmpty(chainSeriesDTO.getChainUnitDTOS())) {
                throw new ServiceException("请初始化设置宠物模板!", HttpStatus.CAN_NOT_FIND);
            }
            Long seriesId = chainSeriesService.create(chainSeriesDTO);
            nftOld.setChainSeriesId(seriesId);
        }

        // 配置限定规则: 道具藏品的补充类型 0其他 1精力 2生命值 3孵化器耐久度（麦盒 聚气丹）4五行本源 5生命值
        if (dto.getSupplementaryType() != null && dto.getSupplementaryType().equals(3)) {
            nftOld.setLimitRule(JSONArray.toJSONString(dto.getLimitSlotPositions()));
        } else if (dto.getSupplementaryType() != null && dto.getSupplementaryType().equals(4)) {
            // 校验是否设置补充数值
            NftAttr nftAttr = dto.getNftAttrs().get(0);
            if (nftAttr.getAttrValue() == null) {
                throw new ServiceException("请指定补充数值!", HttpStatus.CAN_NOT_FIND);
            }
            // 五行本源值配置限定槽位
            if (CollUtil.isEmpty(dto.getLimitSlotPositions())) {
                throw new ServiceException("请指定限定槽位!", HttpStatus.CAN_NOT_FIND);
            }
            nftOld.setLimitRule(JSONArray.toJSONString(dto.getLimitSlotPositions()));
        } else {
            String limitRule = dto.getLimitRule();
            nftOld.setLimitRule(limitRule);
        }

        // 如果是宠物且是圣兽需要校验
        if (dto.getNftType().equals(NftOld.NftTypeEnum.PET.getValue()) && dto.getChainSeriesDTO().getFactionsId() == 2) {
            for (NftAttr nftAttr : dto.getNftAttrs()) {
                if (nftAttr.getAttrValue() <= 0 || nftAttr.getAttrInitValue() <= 0) {
                    throw new ServiceException("参数格式不匹配: 参数值必须大于0", 421);
                }
            }
        }

        //只有实物藏品-除限时活动的藏品修改模拟销量
        if (dto.getNftType() == 5 && dto.getSimulatedSales() != null && !dto.getSimulatedSales().equals(nftOld.getSimulatedSales())) {
            dto.getCategories().forEach(nftCategoryDTOS -> {
                nftCategoryDTOS.forEach(nftCategoryDTO -> {
                    NftCategory nftCategory = new NftCategory();
                    BeanUtils.copyProperties(nftCategoryDTO, nftCategory);
                    if ("限时活动".equals(nftCategory.getName())) {
                        throw new ServiceException("限时活动藏品不能修改模拟销量");
                    }
                });
            });
            nftOld.setSimulatedSales(dto.getSimulatedSales());
        } else {
            nftOld.setSimulatedSales(0);
        }

        // 保存
        this.save(nftOld);


        // 根据文章
        List<Long> list = new ArrayList<>();
        if (CollUtil.isNotEmpty(ids)) {
            // 根据文章id获取专题页
            List<ThemePage> pages = pageService.listByIds(ids);
            // 将类转化为类id对应类的Map形式
            Map<Integer, ThemePage> map = pages.stream().collect(Collectors.toMap(ThemePage::getId, Function.identity()));
            // 遍历文章id, 将藏品的id添加到对应的专题页中
            for (Integer id : ids) {
                ThemePage page = map.get(id);
                // 专题页的id
                String s = page.getIds();   // [1,2]
                if (StringUtils.isNotEmpty(s)) { // 专题的ids不为空
                    String substring = s.substring(1, s.length() - 1);
                    String s1 = substring.replaceAll(" ", "");
                    String[] split = s1.split(",");
                    for (String s2 : split) {
                        if (StringUtils.isNoneBlank(s2) || !s2.equals("")) { // 判断不为空
                            list.add(Long.valueOf(s2));
                        }
                    }
                    if (!list.contains(nftOld.getId())) { // 如果不包含当前藏品id, 就添加进去
                        list.add(nftOld.getId());
                    }
                    if (CollUtil.isNotEmpty(list)) { // 将主题对应的藏品id集合保存
                        List<Long> collect = list.stream().distinct().collect(Collectors.toList());
                        ThemePage themePage = new ThemePage();
                        themePage.setIds(collect.toString());
                        LambdaQueryWrapper<ThemePage> wrapper = new LambdaQueryWrapper<>();
                        wrapper.eq(ThemePage::getId, page.getId());
                        pageService.update(themePage, wrapper);
                    }
                } else {
                    // 添加到s中
                    list.add(nftOld.getId());
                    ThemePage themePage = new ThemePage();
                    themePage.setIds(list.toString());
                    LambdaQueryWrapper<ThemePage> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(ThemePage::getId, page.getId());
                    pageService.update(themePage, wrapper);
                }

            }
//        List<Integer> ids = article.stream().map(ThemePage::getId).collect(Collectors.toList());

        }

        // 如果不是宠物类型, 藏品编号
        if (!nftOld.getNftType().equals(NftOld.NftTypeEnum.PET.getValue())) {
            // 礼包藏品在此执行非常耗时
            generateNum(nftOld.getId(), nftOld.getInitialStock(), dto.getNumRandom(), jsonObject.getString("prefix"));
        }
        // 根据藏品id, 设置藏品分类
        this.insertCategories(dto.getCategories(), nftOld.getId());

        //新增前置购规则
        NftBeforeRule nftBeforeRule = new NftBeforeRule();
        nftBeforeRule.setNftId(nftOld.getId());
        List<HoldPictureDTO> holdPictureDTOs = dto.getHoldPictures();
        for (HoldPictureDTO holdPictureDTO : holdPictureDTOs) {
            BeanUtils.copyProperties(holdPictureDTO, nftBeforeRule);
            nftBeforeRule.setBeforeNfts(JSONObject.toJSONString(holdPictureDTO.getSchemes()));
            nftBeforeRule.setExtraRules(JSONObject.toJSONString(holdPictureDTO.getExtraRules()));
            nftBeforeRule.setRuleType(holdPictureDTO.getRuleType());
            nftBeforeRuleService.save(nftBeforeRule);
        }

        //新增专属购规则
        exclusiveBuyService.add(dto.getNftExclusiveBuyDTOS(), nftOld.getId(), 0);

        //对道具藏品和宠物藏品属性处理, 包括藏品生命, 生产速率, 消耗速率
        Integer nftType = dto.getNftType();
        if (nftType.equals(NftOld.NftTypeEnum.PROP.getValue()) || nftType.equals(NftOld.NftTypeEnum.PET.getValue())) {
            dto.getNftAttrs().forEach(item -> item.setNftId(nftOld.getId()));
            nftAttrService.createNftAttr(dto.getNftAttrs(), nftOld.getId(), 0 + "");
        }

        //对于商品是否分库做处理 todo 不做分库
//        if (dto.getBranchWarehouse().equals(1)) {this.branchWarehouse(dto, nft.getId());}

        //添加积分-礼包藏品 可以发放 1藏品 2玉珠 3天珠 4灵珠 5金核 6木核 7水核 8火核 9土核
        if (CollUtil.isNotEmpty(dto.getIntegral()) && dto.getNftType().equals(NftOld.NftTypeEnum.GIFT.getValue())) {    // 处理礼包中的积分内容
            // 添加礼包
            prizeGiftService.addGift(nftOld.getId(), dto.getIntegral());
        }

        // 礼包类型藏品
        if (!dto.getPrizeGiftList().isEmpty() && dto.getNftType().equals(NftOld.NftTypeEnum.GIFT.getValue())) {    // 处理礼包中的藏品内容
            Integer allStock = nftOld.getStock() + nftOld.getExtraStock();
            dto.getPrizeGiftList().forEach(prizeGift -> {   // 发行的藏品是否足够
                Integer needExtraStock = prizeGift.getGrantNum() * allStock;
                NftOld prizeNftOld = this.getById(prizeGift.getPrizeId());
                if (prizeNftOld.getExtraStock() < needExtraStock) {
                    throw new ServiceException(nftOld.getTitle() + "活动库存不足");
                }
            });

            // 保存道具藏品礼品
            prizeGiftService.addGift(nftOld.getId(), dto.getPrizeGiftList(), PrizeGift.PrizeTypeEnum.NFT.getValue());
            // 遍历设置库存
            dto.getPrizeGiftList().forEach(prizeGift -> {
                Integer needExtraStock = prizeGift.getGrantNum() * allStock;
                NftOld prizeNftOld = this.getById(prizeGift.getPrizeId());
                prizeNftOld.setExtraStock(prizeNftOld.getExtraStock() - needExtraStock);
                this.updateById(prizeNftOld);
            });
        }

    }

    /**
     * 提前生成编号
     *
     * @param nftId
     */
    public void generateNum(Long nftId, Integer stock, Integer numRandom, String prefix) {
        if (stock <= 0) {
            return;
        }
//        redisCache.removeList("self_accretion_" + nftId);    // 删除旧的数据
        List<String> arr = new ArrayList<>();
        for (int i = 1; i <= stock; i++) {
            arr.add(i + "");
        }
        if (numRandom != null && numRandom == 1) {
            Collections.shuffle(arr);
        }
//        redisCache.rightPushAll("self_accretion_" + nftId, arr); // list类型推送藏品编号
        // 写入编号到数据库
        nftNumberService.createNftNumber(nftId, arr, prefix);
    }

    public void insertCategories(List<List<NftCategoryDTO>> dtos, Long nftId) {
        QueryWrapper<NftCategory> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(NftCategory::getNftId, nftId);
        nftCategoryService.remove(queryWrapper);

        List<NftCategory> nftCategories = new ArrayList<>();

        final Integer[] groupId = {0};
        dtos.forEach(nftCategoryDTOS -> {
            groupId[0] += 1;
            nftCategoryDTOS.forEach(nftCategoryDTO -> {
                NftCategory nftCategory = new NftCategory();
                BeanUtils.copyProperties(nftCategoryDTO, nftCategory);
                nftCategory.setNftId(nftId);
                nftCategory.setGroupId(groupId[0]);
                nftCategories.add(nftCategory);
            });
        });

        nftCategoryService.saveBatch(nftCategories);

    }

    public NftOldVO detail(Long id) {
        NftOld nftOld = this.getById(id);
        // 根据id获取藏品
        if (nftOld == null) {
            throw new ServiceException("典藏不存在", 70002);
        }
        NftOldVO nftVO = new NftOldVO();
        // 获取文章id
        String articles = nftOld.getArticles();
        // 主题页面
        List<ThemePage> themePages = null;
        if (StringUtils.isNotEmpty(articles)) {
            String s = articles.substring(1, articles.length() - 1);
            String trim = s.replaceAll(" ", "");
            String[] split = trim.split(",");
            themePages = pageService.listByIds(Arrays.asList(split));
        }
        BeanUtils.copyProperties(nftOld, nftVO);
        // 分类详情
        nftVO.setCategories(nftCategoryService.getCategoryList(id));
        List<ThemePage> pageList = pageService.list(new LambdaQueryWrapper<ThemePage>()
                .isNotNull(ThemePage::getIds));
        for (ThemePage themePage : pageList) {
            if (themePage.getIds() != null) {
                String s1 = themePage.getIds().substring(1, themePage.getIds().length() - 1);
                String trim2 = s1.replaceAll(" ", "");
                String[] split2 = trim2.split(",");
                for (String s2 : split2) {
                    if (!s2.equals("") || !StringUtils.isBlank(s2)) {
                        if (Long.valueOf(s2).equals(id)) {
                            if (themePages != null) {
                                if (!themePages.contains(themePage)) {
                                    themePages.add(themePage);
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
        if (CollUtil.isNotEmpty(themePages)) {
            // 去重
            List<Integer> list = themePages.stream().map(ThemePage::getId).collect(Collectors.toList());
            List<Integer> collect = list.stream().distinct().collect(Collectors.toList());
            List<ThemePage> pages = pageService.listByIds(collect);
            nftVO.setPages(pages);
        }
        if (nftOld.getGiftType() != null && nftOld.getGiftType() == 1 && nftOld.getGiftId() != null) {
            PageResponseVO<MarketingRightsCardVO> vo = rightsCardService.selectPageList(null, nftOld.getGiftId().intValue(), 10, 1);
            if (CollUtil.isNotEmpty(vo.getItems())) {
                nftVO.setMarketingRightsCard(vo.getItems().get(0));
            }
        }

        List<NftBeforeRule> beforeRules = nftBeforeRuleService.list(new LambdaQueryWrapper<NftBeforeRule>().eq(NftBeforeRule::getNftId, id).eq(NftBeforeRule::getRuleType, 1));

        List<HoldPictureVO> holdPictureVOS = new ArrayList<>();

        for (NftBeforeRule nftBeforeRule : beforeRules) {
            HoldPictureVO holdPictureVO = new HoldPictureVO();
            if (nftBeforeRule != null) {
                BeanUtils.copyProperties(nftBeforeRule, holdPictureVO);
                holdPictureVO.setSchemes(JSON.parseArray(nftBeforeRule.getBeforeNfts(), NftBeforeRuleDTO.class));
                holdPictureVO.setExtraRules(JSON.parseArray(nftBeforeRule.getExtraRules(), ExtraRuleDTO.class));
            }
            holdPictureVOS.add(holdPictureVO);
        }

        nftVO.setHoldPictures(holdPictureVOS);
        nftVO.setNftExclusiveBuyDTOS(exclusiveBuyService.getDetail(nftOld.getId(), 0));
        Integer surplusStock = redisCache.getListSize("self_accretion_" + id).intValue();
        nftVO.setSurplusStock(surplusStock);

        //获取商品流通总量........................................................................
        NftCirculateVO nftCirculateVO = nftCirculate(id);
        nftVO.setNum(nftCirculateVO.getNum());
        nftVO.setIsShow(nftCirculateVO.getIsShow());

        //获取藏品持有人数
        Integer num = nftOldService.queryNumberOfHolders(nftOld.getId()) == null ? 0 : nftOldService.queryNumberOfHolders(nftOld.getId());
        nftVO.setNumberOfHolders(num);
        //salesNum 藏品在售数量
        Integer salesNum = sysUserNftMapper.getSalesNum(id.longValue());
        nftVO.setSalesNum(salesNum);

        //分库..................................................................................
        NftRepertorySeparationVo nftRepertorySeparationVo = this.getBranchWarehouse(id);
        if (nftRepertorySeparationVo == null) {
            nftVO.setNftRepertorySeparationVo(new NftRepertorySeparationVo());
        } else {
            nftVO.setNftRepertorySeparationVo(nftRepertorySeparationVo);
        }

        NftRepertorySeparation nftRepertorySeparation = nftRepertorySeparationService.getOne(new LambdaQueryWrapper<NftRepertorySeparation>().eq(NftRepertorySeparation::getNftId, id));
        if (nftRepertorySeparation == null) {
            nftVO.setBranchWarehouse(2);
            //总库存已售 //查询es中的首发的已售订单
//            Integer StockSold = orderMainElasticService.getFirstSoldOrders(id);
//            nftVO.getNftRepertorySeparationVo().setStockSold(StockSold.longValue()); TODO 未分库
            nftVO.getNftRepertorySeparationVo().setStockSold(0L);
        } else {
            nftVO.setBranchWarehouse(1);
        }
        // 设置属性配置, 根据藏品id查询属性配置
        List<NftAttr> nftAttrs = nftAttrService.getTemplateNftAttrs(id);
        nftVO.setNftAttrs(nftAttrs);

        nftVO.setPrizeGiftList(prizeGiftService.prizeGiftList(nftOld.getId(), PrizeGift.PrizeTypeEnum.NFT.getValue()));
        // 礼包积分
        List<PrizeGift> integralVOs = prizeGiftService.getIntegral(nftOld.getId());
        if (integralVOs != null && integralVOs.size() > 0) {
            nftVO.setIntegral(integralVOs);
        }
        //宠物系列详情
        if (nftVO.getNftType().equals(NftOld.NftTypeEnum.PET.getValue())) {
            nftVO.setChainSeriesDTO(chainSeriesService.simpleDetail(nftOld.getChainSeriesId()));
        }
        // 宠物等级
        List<ChainLevelDTO> chainLevelDTOS = ChainSeries.ChainLevelEnum.getValues();
        List<Integer> limitSlotPositions = new ArrayList<>();
        if (nftVO.getLimitType() != null) {
            // 限定方式 0不限制1等级2宠物藏品
            Integer limitType = nftVO.getLimitType();
            switch (limitType) {
                case 1:
                    // 查询限定等级, 然后遍历设置各个等级的选中状态
                    List<Integer> levelIds = JSON.parseArray(nftOld.getLimitRule(), Integer.class);
                    chainLevelDTOS.forEach(chainLevelDTO -> {
                        chainLevelDTO.setIsChoose(levelIds.contains(chainLevelDTO.getLevelId()));
                    });
                    break;
                case 2:
                    List<Long> nftIDs = JSON.parseArray(nftOld.getLimitRule(), Long.class);
                    List<NftOld> nftOlds = new ArrayList<>();
                    // 根据藏品id查询藏品信息
                    if (nftIDs != null && !nftIDs.isEmpty()) {
                        nftOlds = this.list(new LambdaQueryWrapper<NftOld>().in(NftOld::getId, nftIDs));

                    }
                    List<NftOldVO> nftVOS = new ArrayList<>();
                    Mapper mapper = DozerBeanMapperBuilder.buildDefault();
                    nftOlds.forEach(nft1 -> {
                        NftOldVO nftVO1 = mapper.map(nft1, NftOldVO.class);
                        nftVO1.setNumberOfHolders(queryNumberOfHolders(nft1.getId()));
                        NftCirculateVO nftCirculateVO1 = nftCirculate(id);
                        nftVO1.setNum(nftCirculateVO1.getNum());
                        if (nft1.getLevelId() != null && nft1.getLevelId() != 0) {
                            nftVO1.setLevelName(ChainSeries.ChainLevelEnum.toLevel(nft1.getLevelId()).getLevelName());
                        }
                        nftVOS.add(nftVO1);
                    });
                    // 设置限制藏品列表
                    nftVO.setLimitNfts(nftVOS);
                    break;
            }
        }
        // 设置限定等级: 限定等级
        nftVO.setLimitLevels(chainLevelDTOS);
        // 补充类型为孵化器耐久的时候需要解析出来 补充类型 0其他 1精力 2生命值 3孵化器耐久度 4本源 5生命
        if (nftOld.getSupplementaryType() != null && nftOld.getSupplementaryType().equals(3)) {
            List<Integer> list = JSONArray.parseArray(nftOld.getLimitRule(), Integer.class);
            if (CollectionUtils.isNotEmpty(list)) {
                nftVO.setLimitSlotPositions(list);
            } else {
                nftVO.setLimitSlotPositions(new ArrayList<>());
            }
        }
        // 本源的处理
        if (nftOld.getSupplementaryType() != null && nftOld.getSupplementaryType().equals(4)) {
            List<Integer> list = JSONArray.parseArray(nftOld.getLimitRule(), Integer.class);
            if (CollectionUtils.isNotEmpty(list)) {
                nftVO.setLimitSlotPositions(list);
            } else {
                nftVO.setLimitSlotPositions(new ArrayList<>());
            }
        }
        // 查询藏品历史价格
//        Map<String, BigDecimal> historicalPrices = orderMainElasticService.getHistoricalPrices(nft.getId()); todo 未使用es引擎
        Map<String, BigDecimal> map = new HashMap<>();
        map.put("maxPrice", BigDecimal.ZERO);
        map.put("minPrice", BigDecimal.ZERO);
        nftVO.setHistoricalPrices(map);
        return nftVO;
    }


    /**
     * 获取商品流通总量
     *
     * @param nftId
     */
    public NftCirculateVO nftCirculate(Long nftId) {
        //先从缓存中获取
//        RBucket<NftCirculateVO> nftCirculateGrossNftCirculateVORedis = redisCache.getRBucket(nftCirculateGrossRedis + nftId);
//        if (nftCirculateGrossNftCirculateVORedis == null || !nftCirculateGrossNftCirculateVORedis.isExists()) {
        //缓存中没有从数据库中获取，存到redis中
        NftCirculateVO nftCirculate = getNftCirculate(nftId);
//            nftCirculateGrossNftCirculateVORedis.set(nftCirculate, 180, TimeUnit.SECONDS);
        return nftCirculate;
//        }
//        else {//直接从缓存中获取
//            NftCirculateVO nftCirculateVO = nftCirculateGrossNftCirculateVORedis.get();
//            if (nftCirculateVO != null) {
//                return nftCirculateVO;
//            } else {
//                NftCirculateVO nftCirculate = getNftCirculate(nftId);
//                nftCirculateGrossNftCirculateVORedis.set(nftCirculate, 180, TimeUnit.SECONDS);
//                return nftCirculate;
//            }
//
//        }

    }

    /**
     * 从数据库中实时获取商品流通总量
     *
     * @param nftId
     * @return
     */
    public NftCirculateVO getNftCirculate(Long nftId) {
        Integer num = sysUserNftMapper.getNftCirculate(nftId);
        NftOld nftOld = this.getById(nftId);
        NftCirculateVO nftCirculateVO = new NftCirculateVO();
        if (nftOld.getNftCirculateShow() == null) {
            nftOld.setNftCirculateShow(0);
//            this.updateById(nft);
//            nft.setNftCirculateShow(0);

            nftCirculateVO.setIsShow(0);
        } else {
            nftCirculateVO.setIsShow(nftOld.getNftCirculateShow());
        }

        if (num == null) {
            nftCirculateVO.setNum(0);
        } else {
            nftCirculateVO.setNum(num);
        }


        return nftCirculateVO;
    }

    /**
     * 获取藏品持有人数
     *
     * @param id nftId
     * @return
     */
    public Integer queryNumberOfHolders(Long id) {
        //先从缓存中获取
//        RBucket<Integer> numberOfHoldersRedis = redisCache.getRBucket(numberOfHolders + id);
//        RBucket<Integer> numberOfHoldersRedis = null;
//        if (numberOfHoldersRedis == null || !numberOfHoldersRedis.isExists()) {
        //缓存中没有从数据库中获取，存到redis中
        Integer num = sysUserNftMapper.getNumberOfHolders(id);
//            numberOfHoldersRedis.set(num, 180, TimeUnit.SECONDS);
        return num;
//        }
//        else {//直接从缓存中获取
//            Integer num = numberOfHoldersRedis.get();
//            if (num != null) {
//                return num;
//            } else {
//                Integer numData = sysMemberNftMapper.getNumberOfHolders(id);
//                numberOfHoldersRedis.set(numData, 180, TimeUnit.SECONDS);
//                return numData;
//            }
//
//        }
    }

    /**
     * 获取分库库存信息
     *
     * @param id
     * @return
     */
    private NftRepertorySeparationVo getBranchWarehouse(Long id) {
        NftRepertorySeparation nftRepertorySeparation = nftRepertorySeparationService.getOne(new LambdaQueryWrapper<NftRepertorySeparation>().eq(NftRepertorySeparation::getNftId, id));
        NftRepertorySeparation nftRepertorySeparationRd = null;
        if (nftRepertorySeparation != null) {
            //从redis中获取实时库存
//            RBucket<NftRepertorySeparation> nftRepertorySeparationRedis = redisCache.getRBucket(nftRepertorySeparationCreatebeforeRedis + nftRepertorySeparation.getId());
            RBucket<NftRepertorySeparation> nftRepertorySeparationRedis = null;
            if (nftRepertorySeparationRedis == null || !nftRepertorySeparationRedis.isExists()) {
                nftRepertorySeparationRedis.set(nftRepertorySeparation);
            }
            nftRepertorySeparationRd = nftRepertorySeparationRedis.get();
        }

        NftRepertorySeparationVo nftRepertorySeparationVo = new NftRepertorySeparationVo();
        if (nftRepertorySeparation == null) {
            return new NftRepertorySeparationVo();
        }
        if (nftRepertorySeparationRd != null) {
            BeanUtils.copyProperties(nftRepertorySeparationRd, nftRepertorySeparationVo);

            //设置已售件数
            nftRepertorySeparationVo.setOrdinaryRepertorySold(nftRepertorySeparationRd.getOrdinarySold());
            nftRepertorySeparationVo.setPictureRepertorySold(nftRepertorySeparationRd.getPictureSold());
            nftRepertorySeparationVo.setExclusiveRepertorySold(nftRepertorySeparationRd.getExclusiveSold());
            nftRepertorySeparationVo.setStockSold(nftRepertorySeparationRd.getOrdinarySold() + nftRepertorySeparationRd.getPictureSold() + nftRepertorySeparationRd.getExclusiveSold());
            return nftRepertorySeparationVo;
        } else {
            BeanUtils.copyProperties(nftRepertorySeparation, nftRepertorySeparationVo);
            //设置已售件数
            nftRepertorySeparationVo.setOrdinaryRepertorySold(nftRepertorySeparation.getOrdinarySold());
            nftRepertorySeparationVo.setPictureRepertorySold(nftRepertorySeparation.getPictureSold());
            nftRepertorySeparationVo.setExclusiveRepertorySold(nftRepertorySeparation.getExclusiveSold());
            nftRepertorySeparationVo.setStockSold(nftRepertorySeparation.getOrdinarySold() + nftRepertorySeparation.getPictureSold() + nftRepertorySeparation.getExclusiveSold());
            return nftRepertorySeparationVo;
        }


    }

    @Transactional(rollbackFor = Exception.class)
    public void editNft(NftOldDTO dto, Long id) {
        NftOld nftOld = this.getById(id);
        if (nftOld == null) {
            throw new ServiceException("典藏不存在", 70002);
        }
        BeanUtils.copyProperties(dto, nftOld);
        List<Integer> ids = dto.getArticle();
        List<Long> list = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(ids)) {
            List<ThemePage> pages = pageService.listByIds(ids);
            Map<Integer, ThemePage> map = pages.stream().collect(Collectors.toMap(ThemePage::getId, Function.identity()));
            for (Integer id1 : ids) {
                ThemePage page = map.get(id1);
                String s = page.getIds();
                if (StringUtils.isNotEmpty(s)) {
                    String substring = s.substring(1, s.length() - 1);
                    String s1 = substring.replaceAll(" ", "");
                    String[] split = s1.split(",");
                    for (String s2 : split) {
                        if (!s2.equals("") || StringUtils.isNoneBlank(s2)) {
                            list.add(Long.valueOf(s2));
                        }

                    }
                    if (!list.contains(nftOld.getId())) {
                        list.add(nftOld.getId());
                    }
                    if (CollectionUtils.isNotEmpty(list)) {
                        List<Long> collect = list.stream().distinct().collect(Collectors.toList());
                        ThemePage themePage = new ThemePage();
                        themePage.setIds(collect.toString());
                        LambdaQueryWrapper<ThemePage> wrapper = new LambdaQueryWrapper<>();
                        wrapper.eq(ThemePage::getId, page.getId());
                        pageService.update(themePage, wrapper);
                    }
                } else {
                    // 添加到s中
                    list.add(nftOld.getId());
                    ThemePage themePage = new ThemePage();
                    themePage.setIds(list.toString());
                    LambdaQueryWrapper<ThemePage> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(ThemePage::getId, page.getId());
                    pageService.update(themePage, wrapper);
                }
            }
//        List<Integer> ids = article.stream().map(ThemePage::getId).collect(Collectors.toList());
        }
//        nft.setInitialStock(nft.getStock());
        Long currentNftNumSize = redisCache.getListSize("self_accretion_" + id);

        Integer currentAllStock = dto.getStock() + dto.getExtraStock();

        if (currentAllStock > currentNftNumSize.intValue()) {
            throw new ServiceException("活动库存与首发剩余库存之和不能大于剩余编号总数");
        }
        //修改商品流通总量是否显示
        nftOld.setNftCirculateShow(dto.getIsShow());
        nftOld.setOpenPrivilege(dto.getOpenPrivilege());
        //修改积分-礼包藏品
        if (CollectionUtils.isNotEmpty(dto.getIntegral()) && dto.getNftType().equals(NftOld.NftTypeEnum.GIFT.getValue())) {
            prizeGiftService.addGift(nftOld.getId(), dto.getIntegral());
        }
        // 开始关联
        nftOld.setDisplayPngImgs(dto.getDisplayPngImgs());
        if (CollectionUtils.isNotEmpty(ids)) {
            nftOld.setArticles(ids.toString());
        } else {
//            Nft nft1 = new Nft();
//            nft1.setArticles(null);
//            LambdaQueryWrapper<Nft> queryWrapper = new LambdaQueryWrapper<>();
//            queryWrapper.eq(Nft::getId,nft.getId());
//            this.update(nft1,queryWrapper);
            // 不关联任何文章
            List<ThemePage> pages = pageService.list();
            List<ThemePage> idF = pages.stream().filter(themePage -> StringUtils.isNotEmpty(themePage.getIds())).collect(Collectors.toList());
            // 找到关联的文章，删除nft的相关Id

            for (ThemePage s : idF) {
                List<Long> list1 = new ArrayList<>();
                String substring = s.getIds().substring(1, s.getIds().length() - 1);
                String s1 = substring.replaceAll(" ", "");
                String[] split = s1.split(",");
                for (String s2 : split) {
                    if (StringUtils.isNoneBlank(s2)) {
                        if (!Long.valueOf(s2).equals(nftOld.getId())) {
                            list1.add(Long.valueOf(s2));
                        }
                    }
                }
                ThemePage themePage = new ThemePage();
                List<Long> collect = list1.stream().distinct().collect(Collectors.toList());
                themePage.setIds(collect.toString());
                LambdaQueryWrapper<ThemePage> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(ThemePage::getId, s.getId());
                pageService.update(themePage, wrapper);
            }


        }

        nftOld.setArticles(dto.getArticle().toString());
        if (nftOld.getSupplementaryType() != null && nftOld.getSupplementaryType().equals(3)) {
            nftOld.setLimitRule(JSONArray.toJSONString(dto.getLimitSlotPositions()));
        } else {
            String limitRule = dto.getLimitRule();
            nftOld.setLimitRule(limitRule);
        }

        //只有实物藏品-除限时活动的藏品修改模拟销量
        if (dto.getNftType() == 5 && dto.getSimulatedSales() != null && !dto.getSimulatedSales().equals(nftOld.getSimulatedSales())) {
            dto.getCategories().forEach(nftCategoryDTOS -> {
                nftCategoryDTOS.forEach(nftCategoryDTO -> {
                    NftCategory nftCategory = new NftCategory();
                    BeanUtils.copyProperties(nftCategoryDTO, nftCategory);
                    if ("限时活动".equals(nftCategory.getName())) {
                        throw new ServiceException("限时活动藏品不能修改模拟销量");
                    }
                });
            });
            nftOld.setSimulatedSales(dto.getSimulatedSales());
        } else {
            nftOld.setSimulatedSales(0);
        }

        this.updateById(nftOld);
        //修改商品流通总量缓存

        this.insertCategories(dto.getCategories(), nftOld.getId());

        // 如果有发售日历, 将发售日历的时间同步
        nftSellCalendarService.update(new LambdaUpdateWrapper<NftSellCalendar>()
                .eq(NftSellCalendar::getNftId, nftOld.getId())
                .eq(NftSellCalendar::getDateIsDefault, CommonBooleanEnum.IS_TRUE.getValue())
                .set(NftSellCalendar::getSellDate, nftOld.getPublishTime()));

        //        NftBeforeRule nftBeforeRule = new NftBeforeRule();
        //        nftBeforeRule.setNftId(id);
        List<HoldPictureDTO> holdPictureDTOS = dto.getHoldPictures();
        //        nftBeforeRuleService.remove(new LambdaQueryWrapper<NftBeforeRule>().eq(NftBeforeRule::getNftId,id)
        //                .eq(NftBeforeRule::getRuleType,1));
        nftBeforeRuleService.addHoldPicture(nftOld.getId(), holdPictureDTOS, 1);

        //新增专属购规则
        exclusiveBuyService.add(dto.getNftExclusiveBuyDTOS(), nftOld.getId(), 0);

        //礼包送积分编辑
        prizeGiftService.addGift(nftOld.getId(), dto.getIntegral());
        ;
        //对道具藏品属性处理
        Integer nftType = dto.getNftType();
        if (nftType.equals(NftOld.NftTypeEnum.PROP.getValue()) || nftType.equals(NftOld.NftTypeEnum.PET.getValue())) {
            nftAttrService.createNftAttr(dto.getNftAttrs(), nftOld.getId(), 0 + "");
        }

        if (!dto.getPrizeGiftList().isEmpty()) {
            prizeGiftService.addGift(nftOld.getId(), dto.getPrizeGiftList(), PrizeGift.PrizeTypeEnum.NFT.getValue());
        }

        if (dto.getNftType().equals(NftOld.NftTypeEnum.PET.getValue())) {
            ChainSeriesDTO chainSeriesDTO = dto.getChainSeriesDTO();
            chainSeriesService.update(chainSeriesDTO, nftOld.getChainSeriesId());
        }
        //即时限价后清理原非关闭限价状态的缓存(如果有)  update by liqing
        if (nftOld.getResellFixedPriceStatus() == 3) {
            String nftStr = redisTemplate.opsForValue().get("nft:" + nftOld.getId());
            if (StringUtils.isNotEmpty(nftStr)) {
                redisTemplate.delete("nft:" + nftOld.getId());
            }
        }
    }
}
